#include "StatusServiceImpl.hpp"
#include "RedisMgr.hpp"
#include "const.hpp"
#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <cstdint>
#include <grpcpp/support/status.h>
#include <mutex>
#include <string>
std::string generate_unique_string() {
  boost::uuids::uuid uuid = boost::uuids::random_generator()();
  std::string unique_string = boost::uuids::to_string(uuid);
  return unique_string;
}

grpc::Status
StatusServiceImpl::GetChatServer(grpc::ServerContext *context,
                                 const message::GetChatServerReq *request,
                                 message::GetChatServerRsp *reply) {
  std::string prefix("status server has received: ");
  // 获取服务器信息
  const auto &server = getChatServer();
  reply->set_host(server.host);
  reply->set_port(server.port);
  reply->set_error(ErrorCodes::Success);
  reply->set_token(generate_unique_string());
  // 保存用户登录token
  insertToken(request->uid(), reply->token());
  return grpc::Status::OK;
}

StatusServiceImpl::StatusServiceImpl() {
  std::string chatServers = config.get<std::string>("ChatServer.Name", "");
  // 无ChatService
  if (chatServers.empty()) {
    return;
  }
  // 获取所有ChatService的名称 不同ChatService之间用 "," 分隔
  std::vector<std::string> chatServerNames;
  std::stringstream ss(chatServers);
  std::string serverName;
  while (std::getline(ss, serverName, ',')) {
    chatServerNames.push_back(serverName);
  }
  for (std::string &sn : chatServerNames) {
    ChatServer server;
    std::string serverHost = config.get<std::string>(sn + ".Host", "");
    std::string serverPort = config.get<std::string>(sn + ".Port", "");
    std::string serverName = config.get<std::string>(sn + ".Name");
    if (serverName.empty() || serverHost.empty() || serverPort.empty()) {
      continue;
    }
    server.name = serverName;
    server.port = serverPort;
    server.host = serverHost;
    server.con_count = 0;
    _servers[server.name] = server;
  }
}
// 返回连接数量最少的server
ChatServer StatusServiceImpl::getChatServer() {
  std::lock_guard<std::mutex> lock(_server_mutex);
  auto minServer = _servers.begin()->second;
  auto count_str = RedisMgr::GetInstance()->HGet(LOGIN_COUNT, minServer.name);
  if (count_str.empty()) {
    // 不存在默认值，则设置为最大
    minServer.con_count = INT32_MAX;
  } else {
    minServer.con_count = std::stoi(count_str);
  }
  // 遍历所有chatService, 获取其当前连接数量，返回连接数量最少的chatService
  for (auto &server : _servers) {
    if (server.second.name == minServer.name) {
      continue;
    }
    count_str = RedisMgr::GetInstance()->HGet(LOGIN_COUNT, server.second.name);
    if (count_str.empty()) {
      // 不存在默认值，则设置为最大
      server.second.con_count = INT32_MAX;
    } else {
      server.second.con_count = std::stoi(count_str);
    }
    if (server.second.con_count < minServer.con_count) {
      minServer = server.second;
    }
  }
  return minServer;
}

void StatusServiceImpl::insertToken(int uid, const std::string &token) {
  std::string uid_str = std::to_string(uid);
  std::string token_key = USER_TOKEN_PREFIX + uid_str;
  std::string token_value = token;
  RedisMgr::GetInstance()->Set(token_key, token_value);
}

grpc::Status StatusServiceImpl::Login(grpc::ServerContext *context,
                                      const message::LoginReq *request,
                                      message::LoginRsp *reply) {
  auto uid = request->uid();
  auto token = request->token();
  std::string uid_str = std::to_string(uid);
  std::string token_key = USER_TOKEN_PREFIX + uid_str;
  std::string token_value = "";
  bool success = RedisMgr::GetInstance()->Get(token_key, token_value);
  if (!success) {
    reply->set_error(ErrorCodes::UidInvalid);
    return grpc::Status::OK;
  }
  if (token_value != token) {
    reply->set_error(ErrorCodes::TokenInvalid);
    return grpc::Status::OK;
  }
  reply->set_error(ErrorCodes::Success);
  reply->set_uid(uid);
  reply->set_token(token);
  return grpc::Status::OK;
}

StatusServiceImpl::~StatusServiceImpl() {
  std::lock_guard<std::mutex> _server_lock(_server_mutex);
  _servers.clear();
}